////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book:
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
//     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author or Addison-Wesley Longman make no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// Last update: Mar 08, 2003


#ifndef HIERARCHYGENERATORS_INC_
#define HIERARCHYGENERATORS_INC_

#define IS_TYPELIST(TList) TL::Private::IsTypelist<TList>

#include "Typelist.h"
#include "TypeTraits.h"
#include "EmptyType.h"
#include "MSVC6Helpers.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template GenScatterHierarchy
// Generates a scattered hierarchy starting from a typelist and a template
// Invocation (TList is a typelist, Model is a template of one arg):
// GenScatterHierarchy<TList, Model>
// The generated class inherits all classes generated by instantiating the
// template 'Model' with the types contained in TList
////////////////////////////////////////////////////////////////////////////////
//	VC 6.0 changes:
//	* Unit is no longer a template template parameter.
//	* For every concrete unit-template there must be a normal class containing
//	a nested-template class called In. In should only contain a typedef to the
//	concrete Unit.
//
//	Using the originial library one would write something like this:
//	class Foo {};
//	template <class T> struct TestUnit {};
//	void Func(TestUnit<Foo>);
//	int main()
//	{
//		GenScatterHierarchy<Typelist<Foo, NullType>, TestUnit> obj;
//		Func(obj); // calls Func(TestUnit<Foo>)
//	}
//
//	Using this port the code would become:
//	class Foo {};
//	template <class T> struct TestUnit {};
//	struct TestUnitWrapper 
//	{
//		template <class T> struct In {typedef TestUnit<T> type}; 
//	};
//	void Func(TestUnit<Foo>);
//	int main()
//	{
//		GenScatterHierarchy<Typelist<Foo, NullType>, TestUnitWrapper> obj;
//		Func(obj); // calls Func(TestUnit<Foo>)
//	}
//
//	Not very nice, i know :-(
//
//	See "Metaprogramming VC++ - more of Loki ported" from Mat Marcus
//	(http://lists.boost.org/MailArchives/boost/msg20915.php)
//
//	Update:
//	-------
//	The first version of GenScatterHierarchy did not work with typelists
//	containing equal types. The MSVC 6.0 erroneously complains about 
//	inaccessible base-classes (error C2584).
//	This new version adds Dummy-classes to the left branch of the generated
//	hierarchy to workaround this VC-Bug. 
//	It creates hierarchies like this:
//
//						Holder<int>				NullType
//							\					/
//Holder<int>			GenScatter<int>	GenScatter<NullType>
//		\						\		/
//VC_InaccessibleBase		  InheritFromTo
//		  \							|
//GenScatter<int>	GenScatter<TYPELIST_1(int)>
//			\		/
//          InheritFromTo
//				|
//				|		   
//GenScatter<TYPELIST_2(int, int)>
//
//	Of course this version of GenScatterHierarchy generates a lot more
//	classes (5*n) than Alexandrescu's original implementation (3*n)
//	
	
	template <class TList, class Unit> class GenScatterHierarchy;
namespace Private
{
	
	template <class T, class U>
	struct InheritFromTwo : public T, public U
	{	
	};
	
	template <int tag>
	struct GenScatterImpl;

	// Specialization for a general typelist
	template <>
	struct GenScatterImpl<TL::Private::Typelist_ID>
	{
		template <class T, class MetaFunctionWrapper>
		struct In : public GenScatterHierarchy<typename T::Head,MetaFunctionWrapper>
		{
			typedef
			InheritFromTwo	<	VC_InaccessibleBase<GenScatterHierarchy<typename T::Head,
								MetaFunctionWrapper>, typename T::Tail>,
								GenScatterHierarchy<typename T::Tail,
								MetaFunctionWrapper>
							> type;
			typedef VC_InaccessibleBase<GenScatterHierarchy<typename T::Head, MetaFunctionWrapper>,typename T::Tail> LeftBase;
			typedef GenScatterHierarchy<typename T::Tail, MetaFunctionWrapper> RightBase;
		};
	};
	
	// Specialization for a typelist with only one element
	template <>
	struct GenScatterImpl<TL::Private::AtomList_ID>
	{
		template <class T, class MetaFunctionWrapper>
		struct In : public GenScatterHierarchy<typename T::Head,MetaFunctionWrapper>
		{
			// for the last Holder-class no dummy class is needed.
			typedef
			InheritFromTwo	<	GenScatterHierarchy<typename T::Head,
								MetaFunctionWrapper>,
								GenScatterHierarchy<NullType,
								MetaFunctionWrapper>
							> type;
			typedef GenScatterHierarchy<typename T::Head, MetaFunctionWrapper> LeftBase;
			typedef GenScatterHierarchy<NullType, MetaFunctionWrapper> RightBase;
		};
	};
	// Specialization for a single type
	template <>
	struct GenScatterImpl<TL::Private::NoneList_ID>
	{
		template <class AtomicType, class MetaFunctionWrapper>
		struct In
		{
			typedef typename
			ApplyInnerType<MetaFunctionWrapper, AtomicType>::type type;
			typedef type LeftBase;
			typedef EmptyType RightBase;
			//typedef AtomicType::THIS_SELECTED bla;
		};

	};

	// Specialization for NullType
	template <>
	struct GenScatterImpl<TL::Private::NullType_ID>
	{
		template <class NullTypeList, class MetaFunctionWrapper>
		struct In
		{
			typedef EmptyType type;
			typedef type LeftBase;
			typedef type RightBase;
		};
	};
} // end namespace Private
	
	template <class T, class Unit>
	class GenScatterHierarchy : public Private::GenScatterImpl
	<
		IS_TYPELIST(T)::type_id
	>::template In<T, Unit>::type
	{
	public:
		typedef typename Select
		<
			TL::Private::IsTypelist<T>::value, T, void
		>::Result TList;
		
		typedef typename Private::GenScatterImpl
		<
			IS_TYPELIST(T)::type_id
		>::template In<T, Unit>::LeftBase LeftBase;
		typedef typename Private::GenScatterImpl
		<
			IS_TYPELIST(T)::type_id
		>::template In<T, Unit>::RightBase RightBase;
		
		template <typename U> struct Rebind
		{
			typedef ApplyInnerType<Unit, U>::type Result;
		};
	};
	
////////////////////////////////////////////////////////////////////////////////
// function template Field
// Accesses a field in an object of a type generated with GenScatterHierarchy
// Invocation (obj is an object of a type H generated with GenScatterHierarchy,
//     T is a type in the typelist used to generate H):
// Field<T>(obj)
// returns a reference to Unit<T>, where Unit is the template used to generate H
////////////////////////////////////////////////////////////////////////////////
	template <class T, class TList, class UnitWrapper>
	typename ApplyInnerType<UnitWrapper, T>::type&
	Field(GenScatterHierarchy<TList, UnitWrapper>& obj,Type2Type<T>* = (Type2Type<T>*)0)
	{
		return obj;
	}

	template <class T, class TList, class UnitWrapper>
	const typename ApplyInnerType<UnitWrapper, T>::type&
	Field(const GenScatterHierarchy<TList, UnitWrapper>& obj, Type2Type<T>* = (Type2Type<T>*)0)
	{
		return obj;
	}

	

////////////////////////////////////////////////////////////////////////////////
// function template TupleUnit
// The building block of tuples
////////////////////////////////////////////////////////////////////////////////

    template <class T>
    struct TupleUnit
    {
        T value_;
        operator T&() { return value_; }
        operator const T&() const { return value_; }
    };

////////////////////////////////////////////////////////////////////////////////
// class template Tuple
// Implements a tuple class that holds a number of values and provides field
//     access to them via the Field function (below)
////////////////////////////////////////////////////////////////////////////////
	namespace Private
	{
		struct TupleUnitWrapper
		{
			template <class T>
			struct In
			{
				typedef TupleUnit<T> type;
			};
		};
	}
    template <class TList>
	struct Tuple : public GenScatterHierarchy<TList, Private::TupleUnitWrapper>
    {
    };

////////////////////////////////////////////////////////////////////////////////
// helper class template FieldHelper
// See Field below
////////////////////////////////////////////////////////////////////////////////
    
    template <unsigned int i>
    struct FieldHelper
    {            
        template<class H, class Unit>
        struct In
        {
        private:
            typedef typename TL::TypeAt<typename H::TList, i>::Result ElementType;
            typedef typename ApplyInnerType<Unit, ElementType>::type UnitType;
            
            enum { isConst = TypeTraits<H>::isConst };
			
            typedef typename Select
            <
                isConst,
                const typename H::RightBase,
                typename H::RightBase
            > 
            ::Result RightBase;
			
			
            typedef typename Select
            <
                IsEqualType<UnitType, TupleUnit<ElementType> >::value, 
                ElementType, 
                UnitType
            >
            ::Result UnqualifiedResultType;
			
        public:
            typedef typename Select
            <
                isConst,
                const UnqualifiedResultType,
                UnqualifiedResultType
            >
            ::Result ResultType;
            
            // Must be a template, don't know why.
			// If Do is not a template and H& is used as parameter
			// MSVC will give a linker error.
			template <class T>
			static ResultType& Do(H& obj, T*)
            {
                //typedef typename T::RightBase RightBase;
				//RightBase& rightBase = obj;
				RightBase& rightBase = obj;
                return FieldHelper<i - 1>::template In<RightBase, Unit>::Do(rightBase, (int*)0);
            }
        };
    };

    template <>
    struct FieldHelper<0>
    {            
        template<class H, class Unit>
        struct In
        {
        private:
            typedef typename H::TList::Head ElementType;
            typedef typename ApplyInnerType<Unit, ElementType>::type UnitType;
            
            enum { isConst = TypeTraits<H>::isConst };

            typedef typename Select
            <
                isConst,
                const typename H::LeftBase,
                typename H::LeftBase
            > 
            ::Result LeftBase;

            typedef typename Select
            <
                IsEqualType<UnitType, TupleUnit<ElementType> >::value, 
                ElementType, 
                UnitType
            >
            ::Result UnqualifiedResultType;
			
        public:
            typedef typename Select
            <
                isConst,
                const UnqualifiedResultType,
                UnqualifiedResultType
            >
            ::Result ResultType;
            
		public:
            template <class T>
			static ResultType& Do(H& obj, T*)
            {
                LeftBase& leftBase = obj;
                return leftBase;
            }
        };
    };

////////////////////////////////////////////////////////////////////////////////
// function template Field
// Accesses a field in an object of a type generated with GenScatterHierarchy
// Invocation (obj is an object of a type H generated with GenScatterHierarchy,
//     i is the index of a type in the typelist used to generate H):
// Field<i>(obj)
// returns a reference to Unit<T>, where Unit is the template used to generate H
//     and T is the i-th type in the typelist 
////////////////////////////////////////////////////////////////////////////////
	/*
	template <unsigned int i, class TList, class UnitWrapper>
    typename FieldHelper<i>::template In<GenScatterHierarchy<TList, UnitWrapper>,UnitWrapper>::ResultType&
    Field(GenScatterHierarchy<TList, UnitWrapper>& obj, Int2Type<i>)
    {
		typedef typename GenScatterHierarchy<TList, UnitWrapper> H;
		return FieldHelper<i>::template In<H, UnitWrapper>::Do(obj, (int*)0);
    }
	*/
	template <unsigned int i, class TList, class UnitWrapper>
    typename FieldHelper<i>::template In<GenScatterHierarchy<TList, UnitWrapper>,UnitWrapper>::ResultType&
    Field(GenScatterHierarchy<TList, UnitWrapper>& obj, Int2Type<i>* = (Int2Type<i>*)0)
    {
		typedef typename GenScatterHierarchy<TList, UnitWrapper> H;
		return FieldHelper<i>::template In<H, UnitWrapper>::Do(obj, (int*)0);
    }
////////////////////////////////////////////////////////////////////////////////
// class template GenLinearHierarchy
// Generates a linear hierarchy starting from a typelist and a template
// Invocation (TList is a typelist, Model is a template of two args):
// GenScatterHierarchy<TList, Model>
////////////////////////////////////////////////////////////////////////////////
//	VC 6.0 changes:
//	see GenScatterHierarchy 

	template
    <
        class TList,
        class Unit,
        class Root = EmptyType
    >
    class GenLinearHierarchy;

namespace Private
{
    
    template <typename TListTag> 
    struct GenLinearHierarchyHelper
    {
        template<class TList, class Unit, class Root>
        struct In 
        {
            typedef typename TList::ERROR_THIS_INSTANCE_SELECTED Result; 
        };
    };
    
    template <> 
	struct GenLinearHierarchyHelper<TL::Private::Typelist_tag>
    {
        template<class TList, class Unit, class Root>
        struct In 
        {
        private:
            typedef typename TList::Head Head;
            typedef typename TList::Tail Tail;

        public:
            typedef typename
			ApplyInnerType2<Unit, Head, GenLinearHierarchy<Tail, Unit, Root> >::type Result; 
        };
    };

    template <> 
	struct GenLinearHierarchyHelper<TL::Private::NullType_tag>
    {
        template<class TList, class Unit, class Root>
        struct In
        {
        private:
            typedef typename TList::Head Head;

        public:
            typedef typename ApplyInnerType2<Unit,Head, Root>::type Result;
        };
    };
	
	template <class T, class U, class Root>
	struct Wrap
	{
		struct Dummy {};
		typedef typename T::Tail Tail;
		
		// create the hierarchy 
		typedef typename Private::GenLinearHierarchyHelper
          <
			typename TL::Private::IsTypelist<Tail>::type_tag
          >
          ::template In<T, U, Root>::Result TempType;
		
		typedef Private::VC_Base_Workaround<TempType, Dummy> type;
		
		// this is nothing more than a typedef to the created hierarchy (TempType).
		// But if we try to inherit directly from TempType VC 6.0
		// will produce a "Error C2516. : is not a legal base class."
		typedef typename type::LeftBase Base;
	};
} // namespace Private

	// Trying to inherit from LinBase will result in "Error C2516. : is not a legal base class."
	// Private::Wrap introduces some levels of indirections which will
	// make the vc happy.
	template
    <
        class TList,
        class Unit,
        class Root
    >
    class GenLinearHierarchy : public Private::Wrap<TList, Unit, Root>::Base
    {
        ASSERT_TYPELIST(TList); // TList must not be NullType

    public:
        typedef typename Private::GenLinearHierarchyHelper
        <
			typename TL::Private::IsTypelist<typename TList::Tail>::type_tag
        >
        ::template In<TList, Unit, Root>::Result LinBase;
    };

}   // namespace Loki

#if defined (_MSC_VER) && _MSC_VER <= 1300
#define FIELD(Obj, Nr) \
	Field(Obj, (Int2Type<Nr>*)0)
#else
#define FIELD(Obj, Nr) \
	Field<Nr>(Obj)
#endif

////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// September 16, 2002: Fixed dependent template, using "::template" syntax. T.S.
// Oct  24, 2002: ported by Benjamin Kaufmann to MSVC 6 
// Dec	08, 2002: Fixed problems with MSVC6-Version of GenScatterHierarchy when
//					used with typelists containing equal types. B.K.
//					New Version is ugly :-(
// Dec	08, 2002: Interface changed for Field-Function. The old version does not
//					work correctly due to the "Explicitly Specified Template 
//					Functions Not Overloaded Correctly"-Bug 
//					(Microsoft KB Article - 240871). B.K.
// Mar	08, 2003: New transparent workaround for Field-Functions. The FIELD-Macro
//					is no longer needed. B.K.
////////////////////////////////////////////////////////////////////////////////
#undef IS_TYPELIST
#endif // HIERARCHYGENERATORS_INC_
